using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UMC.Net
{

    public abstract class StringSegment
    {
        class EmptySegment : StringSegment
        {
            // ReadOnlyMemory<byte> 

            public override Memory<byte> Memory => Memory<byte>.Empty;
            public override ReadOnlySpan<byte> Span => ReadOnlySpan<byte>.Empty;

            public override Span<byte> Value => Span<byte>.Empty;
            public override StringSegment Slice(int start, int length)
            {
                return this;
            }

            public override void Output(NetWriteData writeData)
            {

            }

            public override int Length => 0;

        }
        class ByteSegment : StringSegment
        {

            private readonly byte[] mValue;
            private readonly int _index;
            private readonly int _length;
            public ByteSegment(byte[] array, int start, int length)
            {

                mValue = array;
                _index = start;
                _length = length;
            }
            public override Span<byte> Value => mValue.AsSpan(_index, _length);
            public override Memory<byte> Memory => mValue.AsMemory(_index, _length);
            public override ReadOnlySpan<byte> Span => mValue.AsSpan(_index, _length);

            public override StringSegment Slice(int start, int length)
            {
                if (start < _length)
                {
                    if (_length - start >= length)
                    {
                        return new ByteSegment(mValue, _index + start, length);
                    }
                    return new ByteSegment(mValue, _index + start, _length - start);

                }
                return Empty;
            }
            public override int Length => _length;
            public override void Output(NetWriteData writeData)
            {
                writeData?.Invoke(mValue, _index, _length);
            }
        }
        public static StringSegment Segment(byte[] bytes, int offset, int count)
        {
            return new ByteSegment(bytes, offset, count);
        }
        public static StringSegment Empty = new EmptySegment();

        public bool IsEmpty
        {
            get
            {
                return this.Length == 0;
            }
        }
        public abstract int Length { get; }
        public abstract ReadOnlySpan<byte> Span
        {
            get;
        }

        public abstract Memory<byte> Memory { get; }// => ReadOnlySpan<byte>.Empty;
        public abstract Span<byte> Value
        {
            get;
        }
        public abstract StringSegment Slice(int start, int length);

        public StringSegment Slice(int start)
        {
            return Slice(start, this.Length - start);
        }
        public abstract void Output(NetWriteData writeData);
        public override string ToString()
        {
            return Span.UTF8();
        }
    }
}
